
#include <cassert>
#include <chrono>
#include <iostream>
#include <vector>
#define NDEBUG
#include "../../include/vararray_old.hpp"
using namespace std;
using namespace std::chrono;
#define STRUCT_
// #define Array_
#define alone
typedef double real;

template <typename T> class vect3 {
public:
  vect3(initializer_list<int> arg) {
    auto p = arg.begin();
    dim[0] = p[0];
    dim[1] = p[1];
    dim[2] = p[2];
    sz = dim[0] * dim[1] * dim[2];
    // elem.resize(sz);
    elem = new T[sz];
  }
  T &operator()(int i, int j, int k) {
    return elem[(i * dim[1] + j) * dim[2] + k];
  }

private:
  T *elem;
  //   array 比原始数组有轻微的优势
  array<int, 3> dim;
  //   int dim[3];
  int sz;
};

struct Coord {
  real x, y, z, xx, yy, ii, jj, kk, ll, mm, nn, tt;
  // real x, y, z;
};

// using vec12 = real[12];

struct vec12 {
  real data[12];
  real &operator[](int i) { return data[i]; }
};

/**
 * @brief
 *       struct              |        array
 *          -O1   -O2        |           -O1     -O2
 *   100*100*100
 *  0.56   0.017   0.013     |  0.73      0.0173  0.013
 *   1000*100*100
 *          0.16    0.12     |            0.174    0.12
 *   1000*1000*100
 *      1.6                               1.72
 *
 *
 * 5个物理量
 *  O1  O2
 *    2.07  1.70           |   2.19   1.8
 * 8个物理量
 * 2.8                     |  2.88
 *
 * 12个物理量
 *   3.9       | 3.9
 * @return int
 */
// 使用struct 性能也很不错  就它了

/**
 * @brief coord 和 结构内是数组的比较
 *
 *  vec12 struct    |     struct
 *     no     -O1    -O2      -O3
 *      33.128      |    34.2
 *  -O1   3.76          |    4.08
 * -O2     3.64         !    3.826
 * -O3     3.63         |    3.62
 * @return int
 */

int main() {
  constexpr int nx{1000}, ny{1000}, nz{100}, nvar{12};
#ifdef STRUCT_
#if 0

    // VarArray<Coord, 3> coord{nx, ny, nz};
    vect3<Coord> coord{nx, ny, nz};
    for (int i = 0; i < nx; ++i)
    {
        for (int j = 0; j < ny; ++j)
        {
            for (int k = 0; k < nz; ++k)
            {
                coord(i, j, k).x = (i * ny * nz + j * nz + k) % 100;
                coord(i, j, k).y = (i * ny * nz + j * nz + k) % 100;
                coord(i, j, k).z = (i * ny * nz + j * nz + k) % 100;
            }
        }
    }

    steady_clock::time_point ts = steady_clock::now();
    for (int i = 0; i < nx; ++i)
    {
        for (int j = 0; j < ny; ++j)
        {
            for (int k = 0; k < nz; ++k)
            {
                coord(i, j, k).x += coord(i, j, k).y * coord(i, j, k).z;
                coord(i, j, k).y -= coord(i, j, k).x * coord(i, j, k).z;
                coord(i, j, k).z += coord(i, j, k).y * coord(i, j, k).x;

                coord(i, j, k).x += coord((i * 12) % nx, j, k).y * coord(i, (j * 10) % ny, k).z;
                coord(i, j, k).y -= coord((i * 21) % nx, j, k).x * coord(i, j, (k * 31) % nz).z;
                coord(i, j, k).z += coord(i, (j * 27) % ny, k).y * coord(i, j, k).x;
            }
        }
    }
    steady_clock::time_point te = steady_clock::now();

#else
  vect3<vec12> coord{nx, ny, nz};
  for (int i = 0; i < nx; ++i) {
    for (int j = 0; j < ny; ++j) {
      for (int k = 0; k < nz; ++k) {
        coord(i, j, k)[0] = (i * ny * nz + j * nz + k) % 100;
        coord(i, j, k)[1] = (i * ny * nz + j * nz + k) % 100;
        coord(i, j, k)[2] = (i * ny * nz + j * nz + k) % 100;
      }
    }
  }

  steady_clock::time_point ts = steady_clock::now();
  for (int i = 0; i < nx; ++i) {
    for (int j = 0; j < ny; ++j) {
      for (int k = 0; k < nz; ++k) {
        coord(i, j, k)[0] += coord(i, j, k)[0] * coord(i, j, k)[0];
        coord(i, j, k)[1] -= coord(i, j, k)[1] * coord(i, j, k)[1];
        coord(i, j, k)[2] += coord(i, j, k)[2] * coord(i, j, k)[2];

        coord(i, j, k)[0] +=
            coord((i * 12) % nx, j, k)[1] * coord(i, (j * 10) % ny, k)[2];
        coord(i, j, k)[1] -=
            coord((i * 21) % nx, j, k)[0] * coord(i, j, (k * 31) % nz)[2];
        coord(i, j, k)[2] += coord(i, (j * 27) % ny, k)[1] * coord(i, j, k)[0];
      }
    }
  }
  steady_clock::time_point te = steady_clock::now();

#endif

#if 0
    vect3<Coord> &coordr = coord;
    steady_clock::time_point ts = steady_clock::now();
    for (int i = 0; i < nx; ++i)
    {
        for (int j = 0; j < ny; ++j)
        {
            for (int k = 0; k < nz; ++k)
            {
                coordr(i, j, k).x += coordr(i, j, k).y * coordr(i, j, k).z;
                coordr(i, j, k).y -= coordr(i, j, k).x * coordr(i, j, k).z;
                coordr(i, j, k).z += coordr(i, j, k).y * coordr(i, j, k).x;

                coordr(i, j, k).x += coordr((i * 12) % nx, j, k).y * coordr(i, (j * 10) % ny, k).z;
                coordr(i, j, k).y -= coordr((i * 21) % nx, j, k).x * coordr(i, j, (k * 31) % nz).z;
                coordr(i, j, k).z += coordr(i, (j * 27) % ny, k).y * coordr(i, j, k).x;
            }
        }
    }
    steady_clock::time_point te = steady_clock::now();
#elif 0
  vect3<Coord> &coordr = coord;
  vect3<Coord> &coordrr = coordr;
  steady_clock::time_point ts = steady_clock::now();
  for (int i = 0; i < nx; ++i) {
    for (int j = 0; j < ny; ++j) {
      for (int k = 0; k < nz; ++k) {
        coordrr(i, j, k).x += coordrr(i, j, k).y * coordrr(i, j, k).z;
        coordrr(i, j, k).y -= coordrr(i, j, k).x * coordrr(i, j, k).z;
        coordrr(i, j, k).z += coordrr(i, j, k).y * coordrr(i, j, k).x;

        coordrr(i, j, k).x +=
            coordrr((i * 12) % nx, j, k).y * coordrr(i, (j * 10) % ny, k).z;
        coordrr(i, j, k).y -=
            coordrr((i * 21) % nx, j, k).x * coordrr(i, j, (k * 31) % nz).z;
        coordrr(i, j, k).z +=
            coordrr(i, (j * 27) % ny, k).y * coordrr(i, j, k).x;
      }
    }
  }
  steady_clock::time_point te = steady_clock::now();
#endif

#endif
#ifdef Array_
  VarArray<real, 4> coord{nx, ny, nz, nvar};
  for (int i = 0; i < nx; ++i) {
    for (int j = 0; j < ny; ++j) {
      for (int k = 0; k < nz; ++k) {
        coord(i, j, k, 0) = (i * ny * nz + j * nz + k) % 100;
        coord(i, j, k, 1) = (i * ny * nz + j * nz + k) % 100;
        coord(i, j, k, 2) = (i * ny * nz + j * nz + k) % 100;
        // coord(i, j, k, 3) = (i * ny * nz + j * nz + k) % 100;
      }
    }
  }

  steady_clock::time_point ts = steady_clock::now();
  for (int i = 0; i < nx; ++i) {
    for (int j = 0; j < ny; ++j) {
      for (int k = 0; k < nz; ++k) {
        coord(i, j, k, 0) += coord(i, j, k, 1) * coord(i, j, k, 2);
        coord(i, j, k, 1) -= coord(i, j, k, 0) * coord(i, j, k, 2);
        coord(i, j, k, 2) += coord(i, j, k, 1) * coord(i, j, k, 0);

        coord(i, j, k, 0) +=
            coord((i * 12) % nx, j, k, 1) * coord(i, (j * 10) % ny, k, 2);
        coord(i, j, k, 1) -=
            coord((i * 21) % nx, j, k, 0) * coord(i, j, (k * 31) % nz, 2);
        coord(i, j, k, 2) += coord(i, (j * 27) % ny, k, 1) * coord(i, j, k, 0);
      }
    }
  }
  steady_clock::time_point te = steady_clock::now();
#endif

  duration<double> dr = duration_cast<duration<double>>(te - ts);
  cout << "\n" << dr.count() << "\n";
  return 0;
}